<?php
class RolesController extends AppController {

	var $name = 'Roles';
	var $helpers = array('Html', 'Form', 'Ajax');
	var $components = array('InheritAcl', 'ControllerList', 'RequestHandler');

	function beforeFilter() {
		parent::beforeFilter();
		//$this->Auth->allow('*');
	}

	function acl()
	{
		$data           = $this->Role->findAll();
		$controllerList = $this->ControllerList->get();

		$aco = new Aco(  );
		$rootAco = $aco->findByAlias( 'controllers' );
		// we loop on all action for all roles
		foreach($controllerList as $controller => $actions ) {
			$controllerAco = $aco->findByAlias( $controller );
			if( empty( $controllerAco ) ) {
				$aco->create(  );
				$aco->save( array ('alias' => $controller, 'parent_id' => $rootAco['Aco']['id']));
				$controllerAco = $aco->findByAlias( $controller );
			}
			foreach($actions as $key => $action) {
				$actionAco = $aco->find( array( 'parent_id' => $controllerAco['Aco']['id'], 'alias' => $action ) );
				if ( empty( $actionAco ) ) {
					$aco->create(  );
					$aco->save( array ('alias' => $action, 'parent_id' => $controllerAco['Aco']['id']));
				}
				$controllerList[$controller][$action] = array();
				unset($controllerList[$controller][$key]);
				foreach($data as $p) {
					$controllerList[$controller][$action][$p['Role']['id']] = $this->Acl->check($p, $controller . '/'. $action, '*');
				}
			}
		}
		$this->set('ctlist', $controllerList);
		$this->set('data', $data);
	}

	// we set unset the permission

	function adjustperm($roleid, $controller, $action, $permission)
	{
		// we read the role again
			
		$role = $this->Role->read(null, $roleid);

		if($action == 'all')
		{
			$controllerList = $this->ControllerList->get();

			foreach($controllerList[$controller] as $action )
			$this->setPermissions($role, $controller, $action, $permission );

			$this->set('ctlist', $controllerList[$controller]);
		}
		else
		{
			$this->setPermissions($role, $controller, $action, $permission );
			$this->set('ctlist',     array($action));
		}

		$this->set('controller', $controller);
		$this->set('permission', $permission);
		$this->set('roleid',     $roleid);
	}

	private function setPermissions($role, $controller, $action, $permission )
	{
		// First check to make sure that the controller is already set up as an ACO

		$aco = new Aco(  );

		$rootAco = $aco->findByAlias( 'ROOT' );

		// Set up $controllerAco if it's not present.

		$controllerAco = $aco->findByAlias( $controller );
		if( empty( $controllerAco ) )
		{
			$aco->create(  );
			$aco->save( array ('alias' => $controller, 'parent_id' => $rootAco['Aco']['id']));
			$controllerAco = $aco->findByAlias( $controller );
		}

		// Set up $actionAcoif it's not present.

		$actionAco = $aco->find( array( 'parent_id' => $controllerAco['Aco']['id'], 'alias' => $action ) );

		if ( empty( $actionAco ) )
		{
			$aco->create(  );
			$aco->save( array ('alias' => $action, 'parent_id' => $controllerAco['Aco']['id']));
			$actionAco = $aco->find( array( 'parent_id' => $controllerAco['Aco']['id'], 'alias' => $action ) );
		}

		// Set up perms now.

		if ( $permission == 'allow' )
		$this->Acl->allow( array( 'model' => 'Role', 'foreign_key' => $role['Role']['id'] ), $controller . '/' . $action );
		else
		$this->Acl->deny( array( 'model' => 'Role', 'foreign_key' => $role['Role']['id'] ), $controller . '/' . $action );
	}

	/**
	 * Rebuild the Acl based on the current controllers in the application
	 *
	 * @return void
	 */
	function buildAcl() {
		$log = array();

		$aco =& $this->Acl->Aco;
		$root = $aco->node('controllers');
		if (!$root) {
			$aco->create(array('parent_id' => null, 'model' => null, 'alias' => 'controllers'));
			$root = $aco->save();
			$root['Aco']['id'] = $aco->id;
			$log[] = 'Created Aco node for controllers';
		} else {
			$root = $root[0];
		}

		App::import('Core', 'File');
		$Controllers = Configure::listObjects('controller');
		$appIndex = array_search('App', $Controllers);
		if ($appIndex !== false ) {
			unset($Controllers[$appIndex]);
		}
		$baseMethods = get_class_methods('Controller');
		$baseMethods[] = 'buildAcl';

		$Plugins = $this->_getPluginControllerNames();
		$Controllers = array_merge($Controllers, $Plugins);

		// look at each controller in app/controllers
		foreach ($Controllers as $ctrlName) {
			App::import('Controller', $ctrlName);
			$ctrlclass = $ctrlName . 'Controller';
			$methods = get_class_methods($ctrlclass);

			// find / make controller node
			$controllerNode = $aco->node('controllers/' . $ctrlName);
			if (!$controllerNode) {
				$aco->create(array('parent_id' => $root['Aco']['id'], 'model' => null, 'alias' => $ctrlName));
				$controllerNode = $aco->save();
				$controllerNode['Aco']['id'] = $aco->id;
				$log[] = 'Created Aco node for ' . $ctrlName;
			} else {
				$controllerNode = $controllerNode[0];
			}

			// clean the methods. to remove those in Controller and private actions.
			foreach ($methods as $k => $method) {
				if (strpos($method, '_', 0) === 0) {
					unset($methods[$k]);
					continue;
				}
				if (in_array($method, $baseMethods)) {
					unset($methods[$k]);
					continue;
				}
				$methodNode = $aco->node('controllers/' . $ctrlName . '/' . $method);
				if (!$methodNode) {
					$aco->create(array('parent_id' => $controllerNode['Aco']['id'], 'model' => null, 'alias' => $method));
					$methodNode = $aco->save();
					$log[] = 'Created Aco node for ' . $method;
				}
			}
		}
		debug($log);
	}

	/**
	 * Get the names of the plugin controllers
	 *
	 * This function will get an array of the plugin controller names, and
	 * also makes sure the controllers are available for us to get the
	 * method names by doing an App::import for each plugin controller.
	 *
	 * @return array List of plugin names
	 */
	function _getPluginControllerNames(){
		App::import('Core', 'File', 'Folder');
		$paths = Configure::getInstance();
		$folder =& new Folder();
		// change directory to the plugins
		$folder->cd(APP . 'plugins');
		// get a list of the files that have a file name that ends with controller.php
		$files = $folder->findRecursive('.*_controller\.php');
		// Get the list of plugins
		$Plugins = Configure::listObjects('plugin');

		// loop through the controllers we found in the plugins directory
		foreach ($files as $f => $fileName) {
			// get the base file name
			$file = basename($fileName);
			// get the controller name
			$file = Inflector::camelize(substr($file, 0, strlen($file) - strlen('_controller.php')));

			// loop through the plugins
			foreach ($Plugins as $pluginName) {
				if (preg_match('/^' . $pluginName . '/', $file)){
					// first, get rid of the App controller for the plugin
					// we do this because the app controller is never called directly
					if (preg_match('/^' . $pluginName . 'App/', $file)) {
						unset($files[$f]);
					} else {
						if (!App::import('Controller', $pluginName . '.' . $file)) {
							debug('Error importing ' . $file . ' for plugin ' . $pluginName);
						}
						// now prepend the Plugin name
						// this is required to allow us to fetch the method names
						$files[$f] = $file;
					}
					break;
				}
			}
		}
		return $files;
	}

	function index() {
		$this->Role->recursive = 0;
		$this->set('roles', $this->paginate());
	}

	function view($id = null) {
		if (!$id) {
			$this->Session->setFlash(__('Invalid Role.', true));
			$this->redirect(array('action'=>'index'));
		}
		$this->set('role', $this->Role->read(null, $id));
	}

	function add() {
		if (!empty($this->data)) {
			$this->Role->create();
			if ($this->Role->save($this->data)) {
				$this->Session->setFlash(__('The Role has been saved', true));
				$this->redirect(array('action'=>'index'));
			} else {
				$this->Session->setFlash(__('The Role could not be saved. Please, try again.', true));
			}
		}
		$roles = $this->Role->find('list');
		$this->set(compact('roles'));
	}

	function edit($id = null) {
		if (!$id && empty($this->data)) {
			$this->Session->setFlash(__('Invalid Role', true));
			$this->redirect(array('action'=>'index'));
		}
		if (!empty($this->data)) {
			//$this->cleanUpFields();
			if ($this->data['Role']['id'] != $this->data['Role']['parent_id']) {
				if ($this->Role->save($this->data)) {
					$this->InheritAcl->checkAroParent('Role', $this->data['Role']['id'], 'Role', $this->data['Role']['parent_id']);
					$this->Session->setFlash(__('The Role has been saved', true));
					$this->redirect(array('action'=>'index'));
				} else {
					$this->Session->setFlash(__('The Role could not be saved. Please, try again.', true));
				}
			}
			else {
				$this->Session->setFlash(__('A role cannot be child of itself.', true));
			}
		}
		if (empty($this->data)) {
			$this->data = $this->Role->read(null, $id);
		}
		$roles = $this->Role->find('list');
		$this->set(compact('roles'));
	}

	function delete($id = null) {
		if (!$id) {
			$this->Session->setFlash(__('Invalid id for Role', true));
			$this->redirect(array('action'=>'index'));
		}
		if ($this->Role->del($id)) {
			$this->Session->setFlash(__('Role deleted', true));
			$this->redirect(array('action'=>'index'));
		}
	}

}
?>